package cn.edu.seu.ssny.controller.web;

import cn.edu.seu.ssny.common.ExportExcelUtils;
import cn.edu.seu.ssny.common.JsonResult;
import cn.edu.seu.ssny.common.utils.DateUtils;
import cn.edu.seu.ssny.controller.BaseController;
import cn.edu.seu.ssny.entity.*;
import cn.edu.seu.ssny.service.IDeviceCategoryService;
import cn.edu.seu.ssny.service.IDeviceDataService;
import cn.edu.seu.ssny.service.IDeviceDataStdService;
import cn.edu.seu.ssny.service.IDeviceService;
import cn.edu.seu.ssny.service.specification.SimpleSpecificationBuilder;
import cn.edu.seu.ssny.service.specification.SpecificationOperator;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.*;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

import static cn.edu.seu.ssny.common.utils.DateUtils.*;
import cn.edu.seu.ssny.common.utils.DateUtils;

@Controller
@RequestMapping("/web/project/usage")
public class UsageController extends BaseController {
    private final static Logger logger = LoggerFactory.getLogger(UsageController.class);


    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private IDeviceDataService deviceDataService;

    @Autowired
    private IDeviceDataStdService deviceDataStdService;

    @Autowired
    private IDeviceCategoryService deviceCategoryService;


    @RequestMapping(value = { "/index"})
    public String index(ModelMap map, HttpSession session) {
        List<DeviceCategory> categories = deviceCategoryService.findByProject((Project) session.getAttribute("currProject"));
        map.put("categories", categories);
        return "web/stat/one";
    }


    @RequestMapping(value = { "/many"})
    public String many(ModelMap map, HttpSession session) {
        List<DeviceCategory> categories = deviceCategoryService.findByProject((Project) session.getAttribute("currProject"));
        map.put("categories", categories);
        return "web/stat/many";
    }

    @RequestMapping(value = { "/table"})
    public String table(ModelMap map, HttpSession session) {
        List<DeviceCategory> categories = deviceCategoryService.findByProject((Project) session.getAttribute("currProject"));
        map.put("categories", categories);
        return "web/stat/table";
    }

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String add(ModelMap map, HttpSession session) {
        Enterprise enterprise = (Enterprise) session.getAttribute("enterprise");
        Specification<Device> specification = new Specification<Device>() {
            @Override
            public Predicate toPredicate(Root<Device> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicatesList = new ArrayList<>();
                predicatesList.add(cb.equal(root.get("enterprise"), enterprise));

                Join<Device, DeviceTemplate> joinTemplate = root.join("template",JoinType.INNER);
                predicatesList.add(cb.equal(joinTemplate.get("isAdd"), true));
                predicatesList.add(cb.isNull(root.get("category")));
                Predicate[] predicates = new Predicate[predicatesList.size()];
                return cb.and(predicatesList.toArray(predicates));
            }
        };
        List<Device> devices = deviceService.findList(specification);
        map.put("devices", devices);
        return "web/stat/add";
    }

    @RequestMapping(value= {"/edit"} ,method = RequestMethod.POST)
    @ResponseBody
    public JsonResult address(ModelMap map, HttpSession session){
        String device_id = request.getParameter("device_id");
        String category_name = request.getParameter("category_name");
        Project project = (Project) session.getAttribute("currProject");
        DeviceCategory category = deviceCategoryService.findByProjectAndName(project, category_name);
        Device device = null;
        if(!device_id.equals(""))
            device = deviceService.find(Integer.parseInt(device_id));
        try {
            deviceService.setCategory(device, category);
        } catch (Exception e) {
            return JsonResult.failure(e.getMessage());
        }
        return JsonResult.success();
    }

    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    public String delete(ModelMap map, HttpSession session) {
        return "web/stat/delete";
    }

    @RequestMapping(value = "/list", method = RequestMethod.POST)
    @ResponseBody
    public Page<DeviceCategory> delList(ModelMap map, HttpSession session) {
        Project project = (Project) session.getAttribute("currProject");

        SimpleSpecificationBuilder<DeviceCategory> builder = new SimpleSpecificationBuilder<DeviceCategory>();
        builder.add("project", SpecificationOperator.Operator.eq.name(), project);
        Page<DeviceCategory> page = deviceCategoryService.findAll(builder.generateSpecification(), getPageRequest());
        System.out.println(page.getSize());
        return page;
    }


    @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
    @ResponseBody
    public JsonResult delete(@PathVariable Integer id, ModelMap map) {
        try {
            deviceCategoryService.delete(id);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.failure(e.getMessage());
        }
        return JsonResult.success();
    }


    @RequestMapping(value = "/device-delete/{id}", method = RequestMethod.GET)
    public String deviceDelete(@PathVariable Integer id, ModelMap map, HttpSession session) {
        map.put("categoryId", id);
        return "web/stat/device-delete";
    }

    @RequestMapping(value = "/device-delete/list/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Page<Device> deviceDeleteList(@PathVariable Integer id, ModelMap map, HttpSession session) {
        DeviceCategory category = deviceCategoryService.find(id);
        int deviceSize = category.getDevices().size();
        if(deviceSize == 0)
            return null;
        Integer[] ids = new Integer[deviceSize];
        for(int i = 0; i < deviceSize; i++){
            ids[i] = category.getDevices().get(i).getId();
            System.out.println(ids[i]);
        }
        Specification<Device> specification = new Specification<Device>() {
            @Override
            public Predicate toPredicate(Root<Device> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicatesList = new ArrayList<>();
                CriteriaBuilder.In inClause = cb.in(root.get("id"));
                for(int id: ids)
                    inClause.value(id);
                predicatesList.add(cb.and(inClause));
                Predicate[] predicates = new Predicate[predicatesList.size()];
                return cb.and(predicatesList.toArray(predicates));
            }
        };
        Page<Device> page = deviceService.findAll(specification, getPageRequest());
        return page;
    }

    @RequestMapping(value = "/device-delete/{categoryId}/{deviceId}", method = RequestMethod.POST)
    @ResponseBody
    public JsonResult delete(@PathVariable Integer categoryId, @PathVariable Integer deviceId, ModelMap map) {
        try {
            Device device = deviceService.find(deviceId);
            deviceService.deleteCategory(device);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.failure(e.getMessage());
        }
        return JsonResult.success();
    }






    @RequestMapping(value= {"/chartOne"} ,method = RequestMethod.POST)
    @ResponseBody
    public JsonResult chartOne(@RequestBody Map<String,Object> jsonMap) {
        Map<String,Object> rtn = packetData(jsonMap, false);
        if(rtn == null) {
            return JsonResult.failure("请选择设备");
        }
        return JsonResult.success("操作成功", rtn);
    }


    private List<String> getDataList(List<Date> timeList, Device device, String mode) {
        List<String> dataList = new ArrayList<>();
        Date start = timeList.get(0);
        Date end = timeList.get(timeList.size()-1);
        Date pre = new Date(start.getTime());
        Date curr = addTime(pre, false, mode, 5);
        Optional<DeviceDataStd> preData = deviceDataStdService.findByDeviceAndCreateTime(device, pre);
        while(!isSameTime(curr, end)) {
            Optional<DeviceDataStd> currData = deviceDataStdService.findByDeviceAndCreateTime(device, curr);
            if(currData.isPresent() && preData.isPresent()) {
                dataList.add(String.valueOf(currData.get().getData() - preData.get().getData()));
            }
            else {
                dataList.add("-");
            }
            preData = currData;
            pre.setTime(curr.getTime());
            curr = addTime(curr, false, mode, 5);
        }
        return dataList;
    }



    private Map<String, Object> packetData(Map<String,Object> jsonMap, boolean isLive) {
        String startTimeSearch = jsonMap.get("startTimeSearch").toString();
        String endTimeSearch = jsonMap.get("endTimeSearch").toString();
        String mode;
        if(isLive) {
            mode = "minute";
        }
        else {
            mode = jsonMap.get("mode").toString();
        }
        JSONObject json = JSONObject.parseObject(JSON.toJSONString(jsonMap));
        JSONArray jsonDevices = json.getJSONArray("selectedDevices");
        List<Device> deviceList = new ArrayList<>();
        for(Object obj: jsonDevices.toArray()) {
            Device device = deviceService.find(Integer.parseInt(obj.toString()));
            deviceList.add(device);
        }
        if(deviceList.size() == 0)
            return null;
        int periodMin = deviceList.get(0).getPeriod()/60;
        Date start;
        Date end;
        if(StringUtils.isNotBlank(endTimeSearch)) { //重设时间
            end = DateUtils.getRoundTime(DateUtils.parseDate(endTimeSearch), periodMin);
        }
        else {
            end = DateUtils.getRoundTime(new Date(), periodMin);
        }
        if(StringUtils.isNotBlank(startTimeSearch)) {
            start = DateUtils.getRoundTime(DateUtils.parseDate(startTimeSearch), periodMin);
        }
        else {
            start = getDefaultStart(end, mode);
        }
        // 能耗需要从上一个开始算
        start = DateUtils.add(start, getTimeMode(mode), -1);
        List<Date> timeList = getTimeList(start, end, isLive, mode, periodMin);
        String tag = null;
        String title = null;
        List<String> legends = new ArrayList<>();
        List<List<String>> yLists = new ArrayList<>();
        for(Object obj: jsonDevices.toArray()){
            Device device = deviceService.find(Integer.parseInt(obj.toString()));
            tag = device.getTemplate().getTag();
            title = device.getCategory().getName();
            legends.add(device.getName());
            yLists.add(getDataList(timeList, device, mode));
        }

        // 消除第一个
        List<String> xList = new ArrayList<>();
        for (int i = 1; i < timeList.size(); i++) {
            xList.add(DateUtils.format(timeList.get(i), getPattern(mode)));
        }

        Map<String, Object> rtn = new HashMap<>();
        rtn.put("xList", xList);
        rtn.put("tag", tag);
        rtn.put("title", title);
        rtn.put("legends", legends);
        rtn.put("yLists", yLists);
        return rtn;
    }

    private List<DeviceData> packetTable(Map<String,Object> jsonMap) {
        String startTimeSearch = jsonMap.get("startTimeSearch").toString();
        String endTimeSearch = jsonMap.get("endTimeSearch").toString();
        String mode;
        mode = jsonMap.get("mode").toString();
        JSONObject json = JSONObject.parseObject(JSON.toJSONString(jsonMap));
        JSONArray jsonDevices = json.getJSONArray("selectedDevices");
        List<Device> deviceList = new ArrayList<>();
        for(Object obj: jsonDevices.toArray()) {
            Device device = deviceService.find(Integer.parseInt(obj.toString()));
            deviceList.add(device);
        }
        if(deviceList.size() == 0)
            return null;
        int periodMin = deviceList.get(0).getPeriod()/60;
        Date start;
        Date end;
        if(StringUtils.isNotBlank(endTimeSearch)) { //重设时间
            end = DateUtils.getRoundTime(DateUtils.parseDate(endTimeSearch), periodMin);
        }
        else {
            end = DateUtils.getRoundTime(new Date(), periodMin);
        }
        if(StringUtils.isNotBlank(startTimeSearch)) {
            start = DateUtils.getRoundTime(DateUtils.parseDate(startTimeSearch), periodMin);
        }
        else {
            start = getDefaultStart(end, mode);
        }
        // 能耗需要从上一个开始算
        start = DateUtils.add(start, getTimeMode(mode), -1);
        List<Date> timeList = getTimeList(start, end, false, mode, periodMin);
        Device device = deviceService.find(Integer.parseInt(jsonDevices.toArray()[0].toString()));
        List<String> dataList =  getDataList(timeList, device, mode);
        List<DeviceData> rtn = new ArrayList<>();
        for(int i = 0; i < dataList.size(); i++) {
            DeviceData deviceData = new DeviceData();
            deviceData.setCreateTime(timeList.get(i+1));
            if(dataList.get(i).equals("-"))
                deviceData.setData(Double.NaN);
            else
                deviceData.setData(Double.parseDouble(dataList.get(i)));
            deviceData.setDevice(device);
            rtn.add(deviceData);
        }
        return rtn;
    }




    @RequestMapping(value= {"/table"} ,method = RequestMethod.POST)
    @ResponseBody
    public JsonResult table(@RequestBody Map<String,Object> jsonMap) {
        List<DeviceData> rtn = packetTable(jsonMap);
        if(rtn == null) {
            return JsonResult.failure("请选择设备");
        }
        return JsonResult.success("操作成功", rtn);
    }

    @RequestMapping(value = { "/tableexport" }, method = RequestMethod.POST)
    @ResponseBody
    public void tableExport(HttpSession session) throws Exception {
        String startTimeSearch = request.getParameter("startTimeSearch");
        String endTimeSearch = request.getParameter("endTimeSearch");
        String mode = request.getParameter("mode");
        Date start = null;
        Date end = null;
        if(StringUtils.isNotBlank(startTimeSearch))
            start = DateUtils.parseDate(startTimeSearch);
        if(StringUtils.isNotBlank(endTimeSearch))
            end = DateUtils.parseDate(endTimeSearch);
        if(start == null || end == null || start.compareTo(end) > 0) { //重设时间
            end = new Date();
            start = getDefaultStart(end, mode);
        }
        List<Date> timeList = getTimeList(start, end, false, mode, 5);
        Device device = deviceService.find(Integer.parseInt(request.getParameter("id")));
        List<String> dataList = getDataList(timeList, device, mode);
        // 去掉第一个
        timeList.remove(timeList.get(0));
        ExcelData data = new ExcelData();
        data.setName("能耗报表");
        List<String> titles = new ArrayList();
        titles.add("序号");
        titles.add("设备名称");
        titles.add("时间");
        titles.add("数值");
        titles.add("单位");
        data.setTitles(titles);

        List<List<Object>> rows = new ArrayList();
        for(int i = 0; i < dataList.size(); i++) {
            List<Object> row = new ArrayList();
            row.add(i+1+"");
            row.add(device.getName());
            row.add(DateUtils.format(timeList.get(i), "yyyy-MM-dd HH:mm:ss"));
            row.add(dataList.get(i));
            row.add(device.getTemplate().getTag());
            rows.add(row);
        }

        data.setRows(rows);
        ExportExcelUtils.exportExcel(response,"table.xlsx",data);
    }
}
